package cn.powertime.evaluation.facade.impl;

import cn.powertime.evaluation.Constants;
import cn.powertime.evaluation.annotation.Facade;
import cn.powertime.evaluation.entity.CpLionUser;
import cn.powertime.evaluation.entity.SysUser;
import cn.powertime.evaluation.entity.SysUserRole;
import cn.powertime.evaluation.exception.BusinessException;
import cn.powertime.evaluation.exception.LoginException;
import cn.powertime.evaluation.facade.SysUserFacade;
import cn.powertime.evaluation.logging.EnumLogType;
import cn.powertime.evaluation.logging.Logging;
import cn.powertime.evaluation.service.CpLionUserService;
import cn.powertime.evaluation.service.SysUserRoleService;
import cn.powertime.evaluation.service.SysUserService;
import cn.powertime.evaluation.shiro.ShiroUtils;
import cn.powertime.evaluation.util.BusinessConstants;
import cn.powertime.evaluation.util.PasswordHelper;
import cn.powertime.evaluation.util.SMSCodeUtils;
import cn.powertime.evaluation.util.TwoTuple;
import cn.powertime.evaluation.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Splitter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author ZYW
 * @since 2019-09-02
 */
@Facade
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public class SysUserFacadeImpl implements SysUserFacade {

    private static final Pattern PHONE_PATTERN = Pattern.compile("^[1][3,4,5,6,7,8][0-9]{9}$");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[0-9a-z]+\\w*@([0-9a-z]+\\.)+[0-9a-z]+$");

    @Autowired
    private SysUserService userService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SMSCodeUtils smsCodeUtils;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CpLionUserService cpLionUserService;

    @Override
    public List<SysUser> selectByAccount(String username) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("account",username);
        wrapper.ne("status", Constants.STATUS_DEL);
        return userService.list(wrapper);
    }

    @Override
    @Logging(code = "sysUser.add",vars = {"addVo.account","addVo"},type = EnumLogType.ADD)
    public boolean add(ReqUserAddVo addVo) {
        boolean b = checkUserNameOnly(addVo.getAccount(), null);
        if (b) {
            throw new BusinessException("账号已经存在");
        }
        /*int smsCode = smsCodeUtils.verifySMSCode(addVo.getSmsCode());
        if(smsCode == -1) {
            throw new BusinessException("验证码输入错误");
        } else if(smsCode == 0) {
            throw new BusinessException("验证码已过期");
        }*/
        Long id = IdWorker.getId();

        SysUser user = new SysUser();
        BeanUtils.copyProperties(addVo, user);
        TwoTuple<String, String> tuple = PasswordHelper.builder().build().encrypt(addVo.getPassword(), String.valueOf(id));
        user.setPassword(tuple.getB());
        user.setPwdSalt(tuple.getA());
        user.setId(id);
        user.setUsername(addVo.getAccount());
        user.setType(BusinessConstants.CLIENT_USER_TYPE);
        LocalDateTime now = LocalDateTime.now();
        user.setCreateTime(now);
        user.setUpdateTime(now);
        user.setModPasswdDate(now);
        return userService.ownSave(user);

    }

    @Override
    @Logging(code = "sysUser.add",vars = {"addVo.account","addVo"},type = EnumLogType.ADD)
    public boolean addLion(RaqLionUserAddVo addVo) {
        boolean b = checkUserNameOnly(addVo.getAccount(), null);
        if (b) {
            throw new BusinessException("账号已经存在");
        }
        /*int smsCode = smsCodeUtils.verifySMSCode(addVo.getSmsCode());
        if(smsCode == -1) {
            throw new BusinessException("验证码输入错误");
        } else if(smsCode == 0) {
            throw new BusinessException("验证码已过期");
        }*/
        Long id = IdWorker.getId();

        SysUser user = new SysUser();
        BeanUtils.copyProperties(addVo, user);
        TwoTuple<String, String> tuple = PasswordHelper.builder().build().encrypt(addVo.getAccount(),addVo.getPassword());
        user.setPassword(tuple.getB());
        user.setPwdSalt(tuple.getA());
        user.setId(id);
        user.setUsername(addVo.getClassifiedName());
        user.setType(BusinessConstants.CLIENT_USER_TYPE_APP);
        user.setNickname(addVo.getNickname());
        LocalDateTime now = LocalDateTime.now();
        user.setCreateTime(now);
        user.setUpdateTime(now);
        user.setModPasswdDate(now);
        user.setAccount(addVo.getAccount());
        CpLionUser cpLionUser = new CpLionUser();
        cpLionUser.setId(id);
        cpLionUser.setUserId(id);
        cpLionUser.setClassifiedGrade(addVo.getClassifiedGrade());
        cpLionUser.setClassifiedName(addVo.getClassifiedName());
        cpLionUser.setClassifiedNumber(addVo.getClassifiedNumber());
        cpLionUser.setCreateTime(now);
        cpLionUser.setUpdateTime(now);
        boolean f= cpLionUserService.ownSave(cpLionUser);
        if(!f){
            throw new BusinessException("注册失败");
        }
        return userService.ownSave(user);

    }

    @Override
    public boolean checkUserNameOnly(String userName, Long id) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("account", userName);
        wrapper.ne("status", Constants.STATUS_DEL);
        if (null != id) {
            wrapper.ne("id", id);
        }
        return userService.count(wrapper) > 0;
    }

    @Override
   // @Logging(code = "sysUser.edit",vars = {"editVo.account","editVo"},type = EnumLogType.UPDATE)
    public boolean edit(ReqSysUserEditVo editVo) {
        if(StringUtils.isNotBlank(editVo.getEmail())){
            Matcher matcher = EMAIL_PATTERN.matcher(editVo.getEmail());
            if(!matcher.matches()){
                throw new BusinessException("邮箱格式不正确");
            }
        }
        SysUser user = new SysUser();
        user.setId(ShiroUtils.getUserInfo().getId());
        BeanUtils.copyProperties(editVo, user);
        user.setUpdateTime(LocalDateTime.now());
        return userService.edit(user);
    }

    @Override
    public boolean accountUpdate(ReqSysUserUpdateReqVo editVo) {
        boolean b = checkUserNameOnly(editVo.getAccount(), ShiroUtils.getUserInfo().getId());
        if (b) {
            throw new BusinessException("账号已存在");
        }
        //验证手机验证码
        //checkMobileCode(editVo);

        SysUser sysUser = userService.findById(ShiroUtils.getUserInfo().getId());
        sysUser.setAccount(editVo.getAccount());
        sysUser.setUpdateTime(LocalDateTime.now());
        return userService.edit(sysUser);
    }

    private void checkMobileCode(ReqSysUserUpdateReqVo editVo){
        Object val = redisTemplate.boundValueOps(editVo.getAccount()).get();
        if(val == null) {
            throw new BusinessException("验证码已过期，请刷新重试！");
        }
        String vcode = String.valueOf(val);
        if(!StringUtils.equals(editVo.getCode(),vcode)) {
            throw new BusinessException("验证码输入错误！");
        }
    }

    @Override
    @Logging(code = "sysUser.del",vars = {"","id"},type = EnumLogType.DEL)
    public boolean del(Long id) {
        SysUser user = userService.getById(id);
        if (user.getDel() == Constants.NO_ALLOW_DEL) {
            throw new BusinessException("当前用户不允许删除");
        }
        user.setStatus(Constants.STATUS_DEL);
        return userService.del(user);
    }

    @Override
    public Page<RespSysUserVo> list(ParamPageVo<ReqSysUserListVo> vo) {
        Page<RespSysUserVo> page = new Page<>(vo.getPage().getCurrent(), vo.getPage().getSize());
        return userService.selectPage(page, vo.getParams());

    }

    @Override
   // @Logging(code = "sysUserPwd.edit",vars = {"vo.id","vo"},type = EnumLogType.UPDATE)
    public boolean updatePwd(ReqSysUserUpdatePwdVo vo) {
        SysUser sysUser = userService.getById(ShiroUtils.getUserInfo().getId());
        String pwd = PasswordHelper.builder().build().encrypt(vo.getOldPassword(), String.valueOf(sysUser.getId()), sysUser.getPwdSalt());
        boolean checkOld = StringUtils.equalsIgnoreCase(pwd,sysUser.getPassword());
        if (!checkOld) {
            throw new BusinessException("旧密码输入不正确");
        }
        String encrypt = PasswordHelper.builder().build().encrypt(vo.getNewPassword(), String.valueOf(sysUser.getId()), sysUser.getPwdSalt());
        boolean checkNew = StringUtils.equalsIgnoreCase(pwd,encrypt);
        if (checkNew) {
            throw new BusinessException("旧密码和新密码相同");
        }
        //根据安全策略验证密码长度及强度是否满足要求
//        QueryWrapper<SysSafeStrategy> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("status", Constants.STATUS_NORMAL);
//        SysSafeStrategy strategy = sysSafeStrategyService.getOne(queryWrapper);
//        if (strategy != null) {
//            int minPassword = strategy.getMinPwdLength();
//            if (vo.getNewPassword().length() < minPassword) {
//                throw new BusinessException("您的密码长度小于系统设定，系统设定最小长度为“" + minPassword + "”");
//            }
//            int passwordStrength = strategy.getPwdIntensity();
//            int score = SafeLevel.score(vo.getNewPassword());
//            if (score < passwordStrength) {
//                throw new BusinessException("您的密码强度小于系统设定，系统设定密码强度为“"+ PasswordLevelEnum.getPasswordLevelEnum(passwordStrength).getNotes()+"”，"+PasswordLevelEnum.getPasswordLevelEnum(passwordStrength).getDesc());
//            }
//        }
        sysUser.setPassword(encrypt);
        sysUser.setModPasswdDate(LocalDateTime.now());

        if(sysUser.getStatus() == Constants.STATUS_RESET_PWD
                || sysUser.getStatus() == Constants.STATUS_PWD_EXPIRE) {
            sysUser.setStatus(Constants.STATUS_NORMAL);
        }
        return userService.edit(sysUser);
    }

    @Override
    //@Logging(code = "sysUserPwd.edit",vars = {"vo.id","vo"},type = EnumLogType.UPDATE)
    public boolean resetPwd(ReqSysUserResetPwdReqVo vo) {
        SysUser sysUser = userService.getById(vo.getId());
        if(sysUser == null) {
            throw new BusinessException("用户不存在");
        }
        String encrypt = PasswordHelper.builder().build().encrypt(vo.getNewPassword(), String.valueOf(sysUser.getId()), sysUser.getPwdSalt());
        sysUser.setPassword(encrypt);
        sysUser.setModPasswdDate(LocalDateTime.now());
        sysUser.setStatus(Constants.STATUS_RESET_PWD);
        return userService.edit(sysUser);
    }

    @Override
    public SysUser details(Long id) {
        return userService.findById(id);
    }

    @Override
    public boolean auth(ReqSysUserAuthVo authVo) {
        //删除用户角色
        QueryWrapper<SysUserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", authVo.getId());
        sysUserRoleService.remove(wrapper);

        //封装用户角色
        String roleIds = authVo.getRoleIds();
        List<String> resIdList = Splitter.on(",").splitToList(roleIds);
        if (null == resIdList || resIdList.isEmpty()) {
            throw new BusinessException("角色信息为空");
        }
        List<SysUserRole> sysRoleResList = resIdList.stream().map(item -> {
            SysUserRole roleRes = new SysUserRole();
            roleRes.setId(IdWorker.getId());
            roleRes.setRoleId(Long.valueOf(item));
            roleRes.setUserId(authVo.getId());
            return roleRes;
        }).collect(Collectors.toList());
        return sysUserRoleService.saveBatch(sysRoleResList);
    }

    @Override
    @Logging(code = "sysUser.del",vars = {"","strings"},type = EnumLogType.DEL)
    public boolean batchDel(List<String> strings) {
        return userService.batchDel(strings);
    }

    @Override
    public boolean updatePwdApp(ReqSysUserUpdatePwdVo vo) {
       SysUser sysUser = new SysUser();
        TwoTuple<String, String> tuple = PasswordHelper.builder().build().encrypt(vo.getAccount() ,vo.getNewPassword());
        sysUser.setPassword(tuple.getB());
        sysUser.setPwdSalt(tuple.getA());
        sysUser.setModPasswdDate(LocalDateTime.now());
        sysUser.setStatus(Constants.STATUS_NORMAL);
        sysUser.setAccount(vo.getAccount());
        return userService.updateByPassword(sysUser);
    }
}
